#define _GNU_SOURCE
#include <stdio.h>
#include "app_serial.h"
#include "../thirdparty/log.h"

/**
 * @brief 设置串口波特率
 *
 * @param baudrate 波特率枚举变量
 * @param dev  设备结构体的指针
 * @return int 成功返回0 失败返回-1
 */
int App_serial_set_baudrate(app_dev_t *dev, SERIAL_BAUD_RATE baudrate)
{
    /*1.声明termios结构体*/
    struct termios termios_attr;
    /*2.使用get方法取出结构体的值*/
    int res = tcgetattr(dev->dev_fd, &termios_attr);
    if (res == -1)
    {
        perror("tchetspeed fail\n");
        return -1;
    }
    /*3.修改termios的值*/
    res = cfsetspeed(&termios_attr, baudrate);
    if (res == -1)
    {
        perror("cfsetspeed fail\n");
        return -1;
    }
    /*4.使用set方法设置修改后的值[暂不生效]*/
    res = tcsetattr(dev->dev_fd, TCSAFLUSH, &termios_attr);
    if (res == -1)
    {
        perror("tcsetattr fail\n");
    }
    return 0;
}

/**
 * @brief 设置停止位函数
 *
 * @param dev 设备指针
 * @param stopbit 停止位枚举变量
 * @return int 成功返回0 失败返回-1
 */
static int App_serial_set_stopbit(app_dev_t *dev, SERIAL_STOP_BIT stopbit)
{
    /*1.声明termios结构体*/
    struct termios termios_attr;
    /*2.使用get方法取出结构体的值*/
    int res = tcgetattr(dev->dev_fd, &termios_attr);
    if (res == -1)
    {
        perror("tchetspeed fail\n");
        return -1;
    }
    /*3.修改termios的值*/
    termios_attr.c_cflag &= ~CSTOPB; // 清除停止位
    termios_attr.c_cflag |= stopbit; // 设置停止位
    /*4.使用set方法设置修改后的值[暂不生效]*/
    res = tcsetattr(dev->dev_fd, TCSAFLUSH, &termios_attr);
    if (res == -1)
    {
        perror("tcsetattr fail\n");
    }
    return 0;
}

/**
 * @brief 设置串口通讯的校验位
 *
 * @param dev 设备指针
 * @param parity 校验位的枚举变量
 * @return int 成功返回0 失败返回-1
 */
static int App_serial_set_parity(app_dev_t *dev, SERIAL_PARITY parity)
{
    /*1.声明termios结构体*/
    struct termios termios_attr;
    /*2.使用get方法取出结构体的值*/
    int res = tcgetattr(dev->dev_fd, &termios_attr);
    if (res == -1)
    {
        perror("tchetspeed fail\n");
        return -1;
    }
    /*3.修改termios的值*/
    termios_attr.c_cflag &= ~(PARENB | PARODD); // 清除校验位
    termios_attr.c_cflag |= parity;             // 设置校验位
    /*4.使用set方法设置修改后的值[暂不生效]*/
    res = tcsetattr(dev->dev_fd, TCSAFLUSH, &termios_attr);
    if (res == -1)
    {
        perror("tcsetattr fail\n");
    }
    return 0;
}

/**
 * @brief 设置串口的原始模式
 *
 * @param dev 设备指针
 * @return int 成功返回0 失败返回-1
 */
static int App_serial_set_makeraw(app_dev_t *dev)
{
    /*1.声明termios结构体*/
    struct termios termios_attr;
    /*2.使用get方法取出结构体的值*/
    int res = tcgetattr(dev->dev_fd, &termios_attr);
    if (res == -1)
    {
        perror("tchetspeed fail\n");
        return -1;
    }
    /*3.修改termios的值*/
    cfmakeraw(&termios_attr);
    /*4.使用set方法设置修改后的值[暂不生效]*/
    res = tcsetattr(dev->dev_fd, TCSAFLUSH, &termios_attr);
    if (res == -1)
    {
        perror("tcsetattr fail\n");
    }
    return 0;
}

/**
 * @brief 设置串口的通信模式
 * 
 * @param dev 设备指针
 * @param mode 通信模式
 * @return int 成功返回0 失败返回-1
 */
int App_serial_set_isblock(app_dev_t* dev,block_mode mode)
{
        /*1.声明termios结构体*/
        struct termios termios_attr;
        /*2.使用get方法取出结构体的值*/
        int res = tcgetattr(dev->dev_fd, &termios_attr);
        if (res == -1)
        {
            perror("tchetspeed fail\n");
            return -1;
        }
        /*3.修改termios的值*/
        if (mode == BLOCK_MODE)
        {
            termios_attr.c_cc[VTIME] = 0;   //无时间限制
            termios_attr.c_cc[VMIN] = 1;    //最少读到一个字符
        }
        else if (mode == NO_BLOCK_MODE)
        {
            termios_attr.c_cc[VTIME] = 2;   //超时时间2s
            termios_attr.c_cc[VMIN]  = 0;   //无字符数量要求
        }
        /*4.使用set方法设置修改后的值[暂不生效]*/
        res = tcsetattr(dev->dev_fd, TCSAFLUSH, &termios_attr);
        if (res == -1)
        {
            perror("tcsetattr fail\n");
        }
        return 0;
}
/**
 * @brief 串口初始化
 *
 * @return int 成功返回0 失败返回-1
 */
int App_serial_Init(app_dev_t *dev)
{
    /*1.设置串口波特率*/
    int res = App_serial_set_baudrate(dev, BR_115200);
    if (res == -1)
    {
        log_error("serial baudrate set fail\n");
        return -1;
    }
    /*2.设置停止位[1位]*/
    res = App_serial_set_stopbit(dev, STOP_BIT_ONE);
    if (res == -1)
    {
        log_error("serial stopbit set fail\n");
    }
    /*3.设置校验位[无校验位]*/
    res = App_serial_set_parity(dev, PARITY_NONE);
    if (res == -1)
    {
        log_error("serial parity set fail\n");
    }
    /*4.设置原始模式*/
    res = App_serial_set_makeraw(dev);
    if (res == -1)
    {
        log_error("serial set makeraw fail\n");
    }
    /*5.设置阻塞模式*/
    res = App_serial_set_isblock(dev,BLOCK_MODE);
    if (res == -1)
    {
        log_error("serial block mode set fail\n");
    }
    /*6.flush生效*/
    res = tcflush(dev->dev_fd,TCIOFLUSH);         //输入输出均生效
    if (res == -1)
    {
        log_error("serial config flush fail\n");
        return -1;
    }
    return 0;
}
